Skip to content

android: strip BOOT_COMPLETED receivers from merged manifest (#4832)#7158

Open
mdmohsin7 wants to merge 1 commit intomainfrom
caleb/android15-boot-receiver-strip
Open

android: strip BOOT_COMPLETED receivers from merged manifest (#4832)#7158
mdmohsin7 wants to merge 1 commit intomainfrom
caleb/android15-boot-receiver-strip

Conversation

@mdmohsin7
Copy link
Copy Markdown
Member

Summary

Google Play rejects targetSdk-35 builds when the merged AndroidManifest wires BOOT_COMPLETED receivers to restricted foreground service types (location, microphone, dataSync, camera, mediaPlayback, phoneCall, mediaProjection).

Two of our plugins inject such receivers via their plugin manifests:

Plugin Receiver Service started FG type
flutter_foreground_task 9.1.0 RebootReceiver ForegroundService location
flutter_background_service_android 6.3.0 BootReceiver BackgroundService microphone

We never opt into autostart at runtime (autoRunOnBoot: false in app/lib/utils/audio/foreground.dart:129, autoStartOnBoot: false in app/lib/services/services.dart:148), so removing the receivers + the dead RECEIVE_BOOT_COMPLETED permission via tools:node="remove" is a no-op at runtime and clears the Play scan.

Why not upgrade the plugins

Both upstreams have unfixed open issues and no shipped workaround:

  • Dev-hwang/flutter_foreground_task — issue #356 open since 2025-07-31, closed #335 without a fix. Latest version 9.2.2 still ships the RebootReceiver declaration.
  • ekasetiawans/flutter_background_service — issues #517 and #518 open since 2025-07-04. Latest 6.3.1 still ships the BootReceiver declaration.

Verification

Ran com.android.tools.build:manifest-merger 32.2.0 locally against the app's AndroidManifest.xml plus both plugin manifests, with --remove-tools-declarations to mirror what AGP does:

Baseline (current main) merged manifest contains:

  • <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  • <receiver android:name="com.pravera.flutter_foreground_task.service.RebootReceiver"> with <action android:name="android.intent.action.BOOT_COMPLETED"/>
  • <receiver android:name="id.flutter.flutter_background_service.BootReceiver"> with <action android:name="android.intent.action.BOOT_COMPLETED"/>

With this PR applied the merged manifest contains:

  • 0 occurrences of BOOT_COMPLETED
  • 0 occurrences of RECEIVE_BOOT_COMPLETED
  • All foreground service declarations preserved (location, microphone, connectedDevice)
  • RestartReceiver and WatchdogReceiver (no boot intent-filter) preserved
$ grep -cE 'BOOT_COMPLETED|RECEIVE_BOOT_COMPLETED' merged-fixed-clean.xml
0

Test plan

  • Codemagic dry-run on caleb/android15-boot-receiver-strip (android-internal-auto) — confirm gradle assembles with no manifest-merger conflict
  • Pull the produced APK from the dry-run artifacts, run aapt2 dump xmltree base.apk --file AndroidManifest.xml, confirm no BOOT_COMPLETED action and no RECEIVE_BOOT_COMPLETED permission
  • After Play Console internal track upload, confirm "Restricted foreground service types" warning no longer appears

Google Play rejects targetSdk 35 builds when the merged AndroidManifest
wires BOOT_COMPLETED receivers to restricted foreground service types
(location, microphone, dataSync, camera, mediaPlayback, phoneCall,
mediaProjection). flutter_foreground_task and flutter_background_service
both inject such receivers via their plugin manifests and neither has
shipped a fix (Dev-hwang/flutter_foreground_task#356,
ekasetiawans/flutter_background_service#517 and #518 are open).

We never opt into autostart (autoRunOnBoot/autoStartOnBoot are false), so
removing the receivers and the dead RECEIVE_BOOT_COMPLETED permission via
tools:node="remove" is a no-op at runtime and clears the Play scan.

Verified by running com.android.tools.build:manifest-merger 32.2.0
locally against the app + plugin manifests with --remove-tools-declarations:
the resulting merged manifest has no BOOT_COMPLETED action, no
RECEIVE_BOOT_COMPLETED permission, and no boot receiver entries, while the
location/microphone/connectedDevice foreground service declarations remain
intact.

Fixes #4832
@mdmohsin7 mdmohsin7 added android bug Something isn't working p2 Priority: Important (score 14-21) labels May 4, 2026
@mdmohsin7
Copy link
Copy Markdown
Member Author

@morpheus review — Approved

Standard Android manifest merger workaround. tools:node="remove" on the permission and both plugin-provided receivers, targeting their fully qualified class names. tools namespace already declared. autoRunOnBoot/autoStartOnBoot both false in Dart — runtime no-op. Clean single commit with issue reference.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 4, 2026

Greptile Summary

This PR fixes a Google Play Store rejection for targetSdk-35 builds by stripping two plugin-injected BOOT_COMPLETED receivers and the RECEIVE_BOOT_COMPLETED permission from the merged AndroidManifest.xml using tools:node="remove". The approach is the correct manifest-merger idiom and is safe given that autoRunOnBoot/autoStartOnBoot are already disabled in the Dart layer.

  • Adds tools:node="remove" to the existing RECEIVE_BOOT_COMPLETED <uses-permission> declaration so neither the app nor any library manifest contributes the permission to the merged output.
  • Inserts two stub <receiver> elements (targeting RebootReceiver from flutter_foreground_task and BootReceiver from flutter_background_service_android) with tools:node="remove" so the plugin manifests' receiver declarations are suppressed during the AGP merge step.

Confidence Score: 5/5

Safe to merge — the change is a targeted manifest-merger override that removes boot-autostart receivers that were never used at runtime.

The diff touches only three manifest declarations: it marks the unused RECEIVE_BOOT_COMPLETED permission and two plugin-injected boot receivers for removal via tools:node="remove". The app already disables both autoRunOnBoot and autoStartOnBoot in Dart, so removing the receivers has no effect on runtime behaviour. The PR author ran the manifest-merger tool locally and confirmed zero BOOT_COMPLETED occurrences in the merged output.

No files require special attention.

Important Files Changed

Filename Overview
app/android/app/src/main/AndroidManifest.xml Adds tools:node="remove" stubs to suppress plugin-injected BOOT_COMPLETED receivers and the RECEIVE_BOOT_COMPLETED permission from the merged manifest; change is minimal, targeted, and verified against the manifest-merger tool.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[AGP Manifest Merger] --> B{Process app AndroidManifest.xml}
    B --> C[RECEIVE_BOOT_COMPLETED\ntools:node=remove]
    B --> D[RebootReceiver stub\ntools:node=remove]
    B --> E[BootReceiver stub\ntools:node=remove]

    F[flutter_foreground_task manifest] --> G[RebootReceiver\nBOOT_COMPLETED intent-filter]
    H[flutter_background_service manifest] --> I[BootReceiver\nBOOT_COMPLETED intent-filter]
    J[App manifest] --> K[RECEIVE_BOOT_COMPLETED\npermission]

    G -->|merger conflict resolution| D
    I -->|merger conflict resolution| E
    K -->|merger conflict resolution| C

    C -->|removed| L[Merged AndroidManifest.xml]
    D -->|removed| L
    E -->|removed| L

    L --> M[0 BOOT_COMPLETED occurrences\n✓ Play Store accepted]
Loading

Reviews (2): Last reviewed commit: "android: strip BOOT_COMPLETED receivers ..." | Re-trigger Greptile

Comment on lines +93 to +98
<receiver
android:name="com.pravera.flutter_foreground_task.service.RebootReceiver"
tools:node="remove" />
<receiver
android:name="id.flutter.flutter_background_service.BootReceiver"
tools:node="remove" />
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Silent failure if boot-autostart is ever re-enabled

These tools:node="remove" stubs permanently strip the boot receivers from the merged manifest. If a future developer sets autoRunOnBoot: true in foreground.dart or autoStartOnBoot: true in services.dart, the receivers will already be gone and the auto-start will silently do nothing on reboot — no crash, no log, just dead configuration. A short inline comment explaining that these override plugin-injected boot receivers (and referencing the disabled autoRunOnBoot/autoStartOnBoot options) would prevent this from becoming a mystery bug.

Comment on lines +38 to +39
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"
tools:node="remove" />
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Plugin library manifests may re-contribute the permission

tools:node="remove" on the app-level <uses-permission> removes the app's own declaration and, in the merger's conflict-resolution pass, prevents lower-priority manifests from winning for the same key. The PR's own verification run (grep -c RECEIVE_BOOT_COMPLETED merged-fixed-clean.xml → 0) confirms this works end-to-end. No action needed — this note is purely for reviewer awareness, and the test plan steps with aapt2 dump on the produced APK will provide definitive confirmation.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 7, 2026

Hey @mdmohsin7 👋

Thank you so much for taking the time to contribute to Omi! We truly appreciate you putting in the effort to submit this pull request.

After careful review, we've decided not to merge this particular PR. Please don't take this personally — we genuinely try to merge as many contributions as possible, but sometimes we have to make tough calls based on:

  • Project standards — Ensuring consistency across the codebase
  • User needs — Making sure changes align with what our users need
  • Code best practices — Maintaining code quality and maintainability
  • Project direction — Keeping aligned with our roadmap and vision

Your contribution is still valuable to us, and we'd love to see you contribute again in the future! If you'd like feedback on how to improve this PR or want to discuss alternative approaches, please don't hesitate to reach out.

Thank you for being part of the Omi community! 💜

@mdmohsin7
Copy link
Copy Markdown
Member Author

#7159 closed the wrong pr

@mdmohsin7 mdmohsin7 reopened this May 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

android bug Something isn't working p2 Priority: Important (score 14-21)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Android 15: BOOT_COMPLETED broadcast restriction crashes foreground service startup

1 participant